package com.szjz.elasticsearch.eshelper.util;

import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;

import java.sql.Time;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author shibo
 * @desc
 * @date 2020/5/16 周六
 */

@Slf4j
public class DateUtils {

	public static final String PATTERN_YYMM = "yyyy-MM";
	public static final String PATTERN_YYMMdd = "yyyy-MM-dd";
	public static final String YYYY_MM_DD = "yyyy_MM_dd";
	public static final String YYYY_MM = "yyyy_MM";
	public static final String MM = "MM";
	public static final String YYYYMMDD = "yyyyMMdd";
	public static final String PATTERN_YYMMddHHmm = "yyyy-MM-dd HH:mm";
	public static final String PATTERN_YYMMDDHHMMSS = "yyyy-MM-dd HH:mm:ss";
	public static final String PATTERN_HHmmss = "HH:mm:ss";

	public static Date parse(String dateStr, String pattern) {
		try {
			return org.apache.commons.lang3.time.DateUtils.parseDate(dateStr, pattern);
		} catch (ParseException e) {
			log.error(e.getMessage());
			throw new RuntimeException("请输入正确的时间格式");
		}
	}

	public static String format(Date date, String pattern) {
		if (date == null || org.springframework.util.StringUtils.isEmpty(pattern)) {
			return null;
		}
		return DateFormatUtils.format(date, pattern);
	}

	/**
	 * 根据传入的时间格式以及时间格式获取当前月的所有日期，这些日期会被给定时间格式进行格式化
	 *
	 * @param time    时间；例如：2015-12-25
	 * @param pattern 时间格式；例如：yyyy-MM-dd
	 * @return 当前月时间列表
	 * @throws ParseException
	 */
	public static List<String> getDatesOfMonth(String time, String pattern) throws ParseException {
		return getDatesOfMonth(time, pattern, null);
	}

	/**
	 * 根据传入的时间格式以及解析该时间格式获取当前月的所有日期，这些日期会被给定时间格式进行格式化
	 *
	 * @param time          时间；例如：2015-12-25
	 * @param parsePattern  解析time所用的时间格式；例如：yyyy-MM-dd
	 * @param formatPattern 格式化这些日期所用的格式；
	 * @return 当前月日期列表
	 * @throws ParseException
	 */
	public static List<String> getDatesOfMonth(String time,
											   String parsePattern,
											   String formatPattern) throws ParseException {
		if (StringUtils.isBlank(formatPattern)) {
			formatPattern = parsePattern;
		}

		List<String> timeStrList = new ArrayList<String>();
		Date date = parse(time, parsePattern);
		Calendar calendar = org.apache.commons.lang3.time.DateUtils.toCalendar(date);
		int month = calendar.get(Calendar.MONTH);
		while (calendar.get(Calendar.MONTH) == month) {
			timeStrList.add(DateFormatUtils.format(calendar.getTime(), formatPattern));
			calendar.add(Calendar.DATE, 1);
		}
		return timeStrList;
	}

	/**
	 * 根据parsePattern解析time，并返回包含time在内的count个月份 例如： getRegionMonths("2015-12", "yyyy-MM", 3) =>
	 * ["2015-10","2015-11","2015-12"]
	 *
	 * @param time         时间；例如：2015-12-25
	 * @param parsePattern 时间格式；例如：yyyy-MM-dd
	 * @param count        月数
	 * @return 时间列表
	 * @throws ParseException
	 */
	public static List<String> getRegionMonths(String time, String parsePattern, int count) throws ParseException {
		String formatPattern = PATTERN_YYMM;
		List<String> timeStrList = new ArrayList<String>();
		Date date = parse(time, parsePattern);
		for (int i = 0; i < count; i++) {
			timeStrList.add(DateFormatUtils.format(date, formatPattern));
			date = org.apache.commons.lang3.time.DateUtils.addMonths(date, -1);
		}
		Collections.reverse(timeStrList);
		return timeStrList;
	}

	/**
	 * 根据parsePattern解析time，并返回包含time在内的count个日期 如果使用的日期格式没有dd，将使用月的第一天作为dd
	 *
	 * @param time         时间；例如：2015-12-25
	 * @param parsePattern 时间格式；例如：yyyy-MM-dd
	 * @param count        天数
	 * @return 时间列表
	 * @throws ParseException
	 */
	public static List<String> getRegionDays(String time, String parsePattern, int count) throws ParseException {
		String formatPattern = PATTERN_YYMMdd;
		List<String> timeStrList = new ArrayList<String>();
		Date date = parse(time, parsePattern);
		for (int i = 0; i < count; i++) {
			timeStrList.add(DateFormatUtils.format(date, formatPattern));
			date = org.apache.commons.lang3.time.DateUtils.addDays(date, -1);
		}
		Collections.reverse(timeStrList);
		return timeStrList;
	}

	//----------------------------------------


	/**
	 * 获取一天当中的最早时刻 00:00:00
	 *
	 * @param beginDateTime 某一天的时间
	 * @return 返回一天当中的最早时刻
	 */
	public static Date getFirstMomentOfDay(Date beginDateTime) {
		try {
			if (beginDateTime != null) {
				String temp = new SimpleDateFormat("yyyy-MM-dd 00:00:00").format(beginDateTime);
				Date begin = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(temp);
				log.debug("first moment of day: {}", begin);
				return begin;
			}
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 获取一天当中的最后时刻 23:59:59
	 *
	 * @param endDateTime 某一天的时间
	 * @return 返回一天当中的最后时刻
	 */
	public static Date getLastMomentOfDay(Date endDateTime) {
		try {
			if (endDateTime != null) {
				String temp = new SimpleDateFormat("yyyy-MM-dd 23:59:59").format(endDateTime);
				Date end = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(temp);
//                log.info("last moment of day: {}", end);
				return end;
			}
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 获取当前周的第一天
	 *
	 * @param now 当前时间
	 * @return 当前周的第一天
	 */
	public static Date getFirstDayOfCurrentWeek(Date now) {
		Calendar cal = Calendar.getInstance();
		try {
			cal.setTime(now);
			cal.set(Calendar.DAY_OF_WEEK, 2);
		} catch (Exception e) {
			e.printStackTrace();
		}

		return cal.getTime();
	}

	/**
	 * 获取当前周最后一天
	 *
	 * @param now 当前时间
	 * @return 当前周最后一天
	 */
	public static Date getLastDayOfCurrentWeek(Date now) {
		Calendar cal = Calendar.getInstance();
		try {
			cal.setTime(now);
			cal.set(Calendar.DAY_OF_WEEK, 1);
			cal.set(Calendar.DATE, cal.get(Calendar.DATE) + 7);
		} catch (Exception e) {
			e.printStackTrace();
		}

		return cal.getTime();
	}


	/**
	 * 获取当前月第一天
	 *
	 * @return 当前月第一天
	 */
	public static Date getFirstDayOfCurrentMonth() {
		Calendar cale = Calendar.getInstance();
		cale.add(Calendar.MONTH, 0);
		cale.set(Calendar.DAY_OF_MONTH, 1);
		return cale.getTime();
	}

	/**
	 * 获取当前月最后一天
	 *
	 * @return 当前月最后一天
	 */
	public static Date getLastDayOfCurrentMonth() {
		Calendar cale = Calendar.getInstance();
		cale.add(Calendar.MONTH, 1);
		cale.set(Calendar.DAY_OF_MONTH, 0);
		return cale.getTime();
	}


	/**
	 * 去掉时分秒 获取：yyyy-MM-dd
	 *
	 * @param date
	 * @return
	 */
	public static Date getDateOfYMD(Date date) {
		try {
			if (date != null) {
				String temp = new SimpleDateFormat("yyyy-MM-dd 00:00:00").format(date);
				Date date1 = new SimpleDateFormat("yyyy-MM-dd").parse(temp);
				return date1;
			} else {
				return null;
			}
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 获取 10-18~10-18 时间格式
	 *
	 * @param star
	 * @param end
	 * @return
	 */
	public static String getMMDDToMMDD(Date star, Date end) {

		String st = null;
		String et = null;
		if (star != null && end != null) {
			st = new SimpleDateFormat("MM-dd").format(star);
			et = new SimpleDateFormat("MM-dd").format(end);
		} else {
			throw new RuntimeException("开始时间或者结束时间不能为空！");
		}
		return st + " ~ " + et;
	}

	public static String getMMDDToMMDD(Date star, Date end, String split) {
		if (split == null) {
			return getMMDDToMMDD(star, end);
		} else {

			String st = null;
			String et = null;
			if (star != null && end != null) {
				st = new SimpleDateFormat("MM'" + split + "'dd日").format(star);
				et = new SimpleDateFormat("MM'" + split + "'dd日").format(end);
			} else {
				throw new RuntimeException("开始时间或者结束时间不能为空！");
			}
			return st + " ~ " + et;
		}
	}

	/**
	 * 以指定的时间间隔(分钟数)为单位增加时间
	 *
	 * @param startTime    原始时间字符串
	 * @param incNum       增加的次数
	 * @param timeInterval 时间间隔
	 * @return
	 */
	public static String increaseHM(String startTime, Integer incNum, Integer timeInterval) {
		String hmStr = startTime;
		String[] hm = hmStr.split(":");
		Integer hour = Integer.valueOf(hm[0]);
		Integer minute = Integer.valueOf(hm[1]);
		for (int i = 0; i < incNum; i++) {
			minute += timeInterval;
		}
		hour = minute / 60 + hour;
		minute = minute % 60;
		String minuteStr = minute == 0 ? "00" : minute.toString();
		hmStr = String.format("%02d", hour) + ":" + minuteStr;
		log.debug("开始时间：{},递增次数：{},结束时间：{}", startTime, incNum, hmStr);
		return hmStr;
	}

	/**
	 * 根据起始时间和结束时间 时间间隔计算时间段数组
	 *
	 * @param startTime    起始时间 12:40
	 * @param endTime      结束时间 15:20   160
	 * @param timeInterval 时间间隔
	 * @return
	 */
	public static List<String> timeListByInterval(String startTime, String endTime, Integer timeInterval) {
		List<String> list = new ArrayList<>();
		String[] startHM = startTime.split(":");
		Integer startHour = Integer.valueOf(startHM[0]);
		Integer startMinute = Integer.valueOf(startHM[1]);

		String[] endHM = endTime.split(":");
		Integer endHour = Integer.valueOf(endHM[0]);
		Integer endMinute = Integer.valueOf(endHM[1]);

		int totalMinute = (endHour - startHour) * 60 + (endMinute - startMinute);
		int totalIncNum = totalMinute / timeInterval;

		for (int i = 0; i < totalIncNum + 1; i++) {
			String hm = increaseHM(startTime, i, timeInterval);
			list.add(hm);
		}
		log.debug("起始时间:{},结束时间:{},总分钟数：{},总增加次数：{}", startTime, endTime, totalMinute, totalIncNum);
		log.debug("时间段数组：{}", list);

		//如果不能按照时间间隔平均分配 那么将会议室使用的结束时间作为最后一个时间段的最后时间
		String last = list.get(list.size() - 1);
		if (!last.equals(endTime)) {
			list.remove(list.size() - 1);
			list.add(endTime);
		}
		return list;
	}


	/**
	 * 功能描述: 根据日期获取周几
	 *
	 * @param now 当天时间
	 * @return 具体的周
	 */
	public static String getWeekOfDate(Date now) {
		String[] weekDays = {"周日", "周一", "周二", "周三", "周四", "周五", "周六"};
		Calendar cal = Calendar.getInstance();
		cal.setTime(now);
		int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
		if (w < 0) {
			w = 0;
		}
		return weekDays[w];
	}


	/**
	 * 日期差天数、小时、分钟、秒数组
	 *
	 * @param startDate
	 * @param endDate
	 * @return
	 */
	public static long[] getDisTime(Date startDate, Date endDate) {
		long timesDis = Math.abs(startDate.getTime() - endDate.getTime());
		long day = timesDis / (1000 * 60 * 60 * 24);
		long hour = timesDis / (1000 * 60 * 60) - day * 24;
		long min = timesDis / (1000 * 60) - day * 24 * 60 - hour * 60;
		long sec = timesDis / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60;
		return new long[]{day, hour, min, sec};
	}

	/**
	 * 日期差天数
	 *
	 * @param startDate
	 * @param endDate
	 * @return
	 */
	public static long getDisDay(Date startDate, Date endDate) {
		long[] dis = getDisTime(startDate, endDate);
		long day = dis[0];
//        if (dis[1] > 0 || dis[2] > 0 || dis[3] > 0) {
//            day += 1;
//        }
		return day;
	}


	/**
	 * 获取指定日期N天以前的时间
	 *
	 * @param date   指定的日期
	 * @param dayNum 间隔的天数
	 * @return
	 */
	public static Date getDateBefore(Date date, int dayNum) {
		Calendar now = Calendar.getInstance();
		now.setTime(date);
		now.set(Calendar.DATE, now.get(Calendar.DATE) - dayNum);
		return now.getTime();
	}

	public static void main(String[] args) {
		Date dateBefore = getDateBefore(new Date(), 15);
		System.out.println(dateBefore);
	}

	/**
	 * 昨天
	 */
	public static Date getYesterday() {
		return getDateBefore(new Date(), 1);
	}

	/**
	 * 获取指定日期N天以后的时间
	 *
	 * @param date   指定的日期
	 * @param dayNum 间隔的天数
	 * @return
	 */
	public static Date getDateAfter(Date date, int dayNum) {
		Calendar now = Calendar.getInstance();
		now.setTime(date);
		now.set(Calendar.DATE, now.get(Calendar.DATE) + dayNum);
		return now.getTime();
	}

	public static String getCurrentTimeAsString() {
		Date date = new Date();
		DateFormat df = new SimpleDateFormat("yyMMddHHmmss");
		return df.format(date);
	}


	/**
	 * @param time
	 * @return
	 */
	public static String timeToStr(Time time) {
		return time.toString().substring(0, 5);
	}

	public static java.sql.Date utilDateToSqlDate(Date utilDate) {

		return new java.sql.Date(utilDate.getTime());
	}

	public static Date sqlDateToUtilDate(java.sql.Date sqlDate) {
		return new Date(sqlDate.getTime());
	}

	public static String longToYMDStr(Long l) {
		if (l == null) {
			return null;
		}
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		return format.format(l);
	}

	public static String longToHMSStr(Long l) {
		if (l == null) {
			return null;
		}
		SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
		return format.format(l);
	}

	/**
	 * 获取最近n天的日期数组
	 */
	public static List<String> getLastDays(Integer day, Date date) {
		List<String> list = new ArrayList<>();
		for (int i = 0; i < day; i++) {
			list.add(format(getDateBefore(date, i), PATTERN_YYMMdd));
		}
		return list;
	}


	public static Date getStartDayTime(int day) {
		Calendar todayStart = Calendar.getInstance();
		todayStart.set(Calendar.HOUR_OF_DAY, 0);
		todayStart.set(Calendar.MINUTE, 0);
		todayStart.set(Calendar.SECOND, 0);
		todayStart.set(Calendar.MILLISECOND, 0);
		todayStart.add(Calendar.DAY_OF_MONTH, day);
		return todayStart.getTime();
	}

	public static Date getEndDayTime(int day) {
		Calendar todayEnd = Calendar.getInstance();
		todayEnd.set(Calendar.HOUR_OF_DAY, 23);
		todayEnd.set(Calendar.MINUTE, 59);
		todayEnd.set(Calendar.SECOND, 59);
		todayEnd.set(Calendar.MILLISECOND, 999);
		todayEnd.add(Calendar.DAY_OF_MONTH, day);
		return todayEnd.getTime();
	}

	/**
	 * CST转换为Date
	 */
	public static Date CSTToDate(String str) {
		SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US);
		try {
			return sdf.parse(str);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 计算2个日期之间相差的  相差多少年月日
	 * 比如：2011-02-02 到  2017-03-02 相差 6年，1个月，0天
	 *
	 * @param startDate
	 * @param endDate
	 * @return
	 */
	public static DayCompare dateCompare(Date startDate, Date endDate) {
		Calendar start = Calendar.getInstance();
		start.setTime(startDate);
		Calendar end = Calendar.getInstance();
		end.setTime(endDate);

		int startYear = start.get(Calendar.YEAR);
		int startMonth = start.get(Calendar.MONTH);
		int startDay = start.get(Calendar.DAY_OF_MONTH);

		int endYear = end.get(Calendar.YEAR);
		int endMonth = end.get(Calendar.MONTH);
		int endDay = end.get(Calendar.DAY_OF_MONTH);
		int diffYear = endYear - startYear;
		int diffMonth = endMonth - startMonth;
		int diffDay = endDay - startDay;
		return DayCompare.builder().diffDay(diffDay).diffMonth(diffMonth).diffYear(diffYear).build();
	}

	@Data
	@Builder
	public static class DayCompare {
		/**
		 * day
		 */
		private int diffDay;

		/**
		 * month
		 */
		private int diffMonth;

		/**
		 * year
		 */
		private int diffYear;

	}
}
